/**
 * 数据监控模块
 * 提供数据操作日志、一致性检查和性能监控功能
 */

const cloudBase = require('../../../framework/cloud/cloud_base.js');
const util = require('../../../framework/helpers/util.js');
const timeUtil = require('../../../framework/helpers/time_util.js');

// 监控配置
const MONITOR_CONFIG = {
  // 是否启用完整监控
  enabled: true,
  
  // 日志级别: debug, info, warn, error
  logLevel: 'info',
  
  // 是否记录数据操作到日志表
  logDataOperations: true,
  
  // 性能监控阈值(ms)
  performanceThresholds: {
    query: 500,   // 查询操作超过500ms记录警告
    update: 800,  // 更新操作超过800ms记录警告
    insert: 1000, // 插入操作超过1000ms记录警告
  },
  
  // 是否启用定期一致性检查
  enableConsistencyCheck: true,
  
  // 一致性检查间隔(ms) - 1小时
  consistencyCheckInterval: 3600000,
  
  // 告警配置
  alerts: {
    enabled: true,
    // 错误数量阈值，超过后触发告警
    errorThreshold: 5,
    // 告警接收人
    recipients: ['admin', 'director'],
    // 冷却时间(ms) - 1小时内不重复发送同类告警
    cooldown: 3600000
  }
};

// 记录的操作类型
const OPERATION_TYPES = {
  INSERT: 'insert',
  UPDATE: 'update',
  DELETE: 'delete',
  QUERY: 'query',
  VALIDATE: 'validate',
  CONSISTENCY_CHECK: 'consistency_check'
};

// 最近错误缓存
const errorCache = {
  errors: [],
  lastAlertTime: 0
};

/**
 * 记录数据操作日志
 * @param {string} operation 操作类型
 * @param {string} collection 集合名
 * @param {Object|string} data 操作数据或ID
 * @param {Object} metadata 元数据
 * @returns {Promise<string>} 日志ID
 */
async function logOperation(operation, collection, data, metadata = {}) {
  if (!MONITOR_CONFIG.enabled || !MONITOR_CONFIG.logDataOperations) {
    return null;
  }
  
  try {
    // 获取当前用户信息
    const cloud = cloudBase.getCloud();
    const wxContext = cloud.getWXContext();
    
    // 准备日志数据
    const logData = {
      operation: operation,
      collection: collection,
      timestamp: timeUtil.time(),
      userId: wxContext.OPENID || 'system',
      userIp: wxContext.CLIENTIP || '',
      
      // 根据操作类型处理数据字段
      dataId: typeof data === 'string' ? data : (data._id || ''),
      
      // 对于INSERT和UPDATE操作，记录字段数量而非完整数据
      dataFields: typeof data === 'object' ? 
        {
          count: Object.keys(data).length,
          names: Object.keys(data).slice(0, 20) // 最多记录20个字段名
        } : null,
      
      // 附加元数据
      metadata: {
        ...metadata,
        duration: metadata.duration || 0,
        success: metadata.success !== false
      }
    };
    
    // 如果是错误操作，记录错误信息
    if (metadata.error) {
      logData.error = {
        message: metadata.error.message || String(metadata.error),
        stack: metadata.error.stack || ''
      };
    }
    
    try {
      // 写入日志表
      const db = cloud.database();
      const result = await db.collection('plm_data_operations_log').add({
        data: logData
      });
      
      // 检查是否需要触发告警
      if (metadata.error && MONITOR_CONFIG.alerts.enabled) {
        errorCache.errors.push({
          operation,
          collection,
          timestamp: logData.timestamp,
          message: logData.error.message
        });
        
        // 清理超过1小时的错误
        const oneHourAgo = logData.timestamp - 3600;
        errorCache.errors = errorCache.errors.filter(e => e.timestamp >= oneHourAgo);
        
        // 检查是否达到告警阈值
        if (errorCache.errors.length >= MONITOR_CONFIG.alerts.errorThreshold) {
          // 检查冷却时间
          const now = timeUtil.time();
          if (now - errorCache.lastAlertTime > MONITOR_CONFIG.alerts.cooldown) {
            await triggerAlert(errorCache.errors);
            errorCache.lastAlertTime = now;
            errorCache.errors = [];
          }
        }
      }
      
      return result._id;
    } catch (dbError) {
      // 集合可能不存在，或者其他数据库错误
      // 输出警告但不阻止应用继续运行
      console.warn('[数据监控] 无法记录到数据库，降级到控制台输出:', dbError.message);
      console.log('[数据监控记录]', JSON.stringify(logData));
      
      // 检查是否是集合不存在错误
      if (dbError.message && dbError.message.includes('collection not exists')) {
        // 尝试创建集合
        try {
          console.log('[数据监控] 尝试创建缺失的集合...');
          await db.createCollection('plm_data_operations_log');
          console.log('[数据监控] 创建集合成功，下次操作将正常记录');
        } catch (createError) {
          console.warn('[数据监控] 无法创建集合:', createError.message);
        }
      }
      
      return null;
    }
    
  } catch (error) {
    // 日志系统自身错误，仅在控制台输出
    console.error('[数据监控] 记录操作日志失败:', error);
    return null;
  }
}

/**
 * 触发告警
 * @param {Array} errors 错误信息数组
 */
async function triggerAlert(errors) {
  try {
    // 准备告警消息
    const message = {
      title: `数据操作告警: 检测到${errors.length}个错误`,
      content: errors.map(e => 
        `[${timeUtil.formatTime(e.timestamp)}] ${e.operation} ${e.collection}: ${e.message}`
      ).join('\n'),
      timestamp: timeUtil.time(),
      recipients: MONITOR_CONFIG.alerts.recipients
    };
    
    // 写入告警表
    const cloud = cloudBase.getCloud();
    const db = cloud.database();
    
    try {
      await db.collection('plm_system_alerts').add({
        data: message
      });
      
      console.warn(`[数据监控] 触发告警: ${message.title}`);
    } catch (dbError) {
      // 集合可能不存在，输出警告并继续
      console.warn('[数据监控] 无法记录告警到数据库:', dbError.message);
      console.log('[数据监控告警]', JSON.stringify(message));
      
      // 检查是否是集合不存在错误
      if (dbError.message && dbError.message.includes('collection not exists')) {
        // 尝试创建集合
        try {
          console.log('[数据监控] 尝试创建告警集合...');
          await db.createCollection('plm_system_alerts');
          console.log('[数据监控] 创建告警集合成功，下次告警将正常记录');
          
          // 再次尝试写入
          await db.collection('plm_system_alerts').add({
            data: message
          });
        } catch (createError) {
          console.warn('[数据监控] 无法创建告警集合:', createError.message);
        }
      }
    }
    
    return true;
  } catch (error) {
    console.error('[数据监控] 触发告警失败:', error);
    return false;
  }
}

/**
 * 性能监控包装器
 * @param {Function} operationFn 要监控的操作函数
 * @param {string} operationType 操作类型
 * @param {string} collection 集合名
 * @param {Object|string} data 操作数据或ID
 * @param {Object} metadata 额外元数据
 * @returns {Promise<any>} 操作结果
 */
async function monitorPerformance(operationFn, operationType, collection, data, metadata = {}) {
  console.log(`[数据监控] 开始监控 ${operationType} 操作，集合:${collection}`);
  
  if (!MONITOR_CONFIG.enabled) {
    console.log('[数据监控] 监控功能已禁用，直接执行操作');
    try {
      return await operationFn();
    } catch (directError) {
      console.error('[数据监控] 直接执行操作失败:', directError);
      throw directError;
    }
  }
  
  const startTime = Date.now();
  let success = true;
  let error = null;
  let result = null;
  
  try {
    // 执行操作
    console.log(`[数据监控] 执行 ${operationType} 操作...`);
    result = await operationFn();
    console.log(`[数据监控] ${operationType} 操作成功完成`);
    return result;
  } catch (err) {
    success = false;
    error = err;
    console.error(`[数据监控] ${operationType} 操作失败:`, err.message);
    console.error('[数据监控] 错误详情:', err);
    throw err;
  } finally {
    try {
      // 计算持续时间
      const duration = Date.now() - startTime;
      
      // 检查是否超过性能阈值
      const threshold = MONITOR_CONFIG.performanceThresholds[operationType] || 1000;
      const isSlowOperation = duration > threshold;
      
      if (isSlowOperation) {
        console.warn(`[数据监控] 检测到慢操作: ${operationType} 用时 ${duration}ms，超过阈值 ${threshold}ms`);
      }
      
      // 记录日志（无论成功失败）
      const logMetadata = {
        ...metadata,
        duration: duration,
        success: success,
        error: error,
        isSlowOperation: isSlowOperation
      };
      
      try {
        // 尝试记录日志，但不要让日志错误影响主流程
        await logOperation(operationType, collection, data, logMetadata);
      } catch (logError) {
        // 日志记录失败不应该影响主操作
        console.warn('[数据监控] 记录操作日志时出错:', logError.message);
      }
    } catch (finallyError) {
      // 确保finally块中的错误不会传播
      console.error('[数据监控] finally块执行出错:', finallyError);
    }
  }
}

/**
 * 检查数据一致性
 * @param {Array} projects 项目数据数组
 * @returns {Object} 一致性检查结果
 */
async function checkDataConsistency(projects) {
  const results = {
    total: projects.length,
    passed: 0,
    failed: 0,
    warnings: 0,
    issues: []
  };
  
  for (const project of projects) {
    // 检查项目必要字段是否存在
    const requiredFields = ['_id', 'model', 'projectType', 'level1'];
    const missingFields = [];
    
    for (const field of requiredFields) {
      if (!project[field] && project[field] !== 0) {
        missingFields.push(field);
      }
    }
    
    // 检查扩展字段
    let extDataIssues = [];
    if (project.extData) {
      if (typeof project.extData !== 'object') {
        extDataIssues.push('extData不是对象类型');
      } else {
        // 检查扩展字段中是否存在核心字段
        const coreFields = ['_id', 'model', 'projectType', 'level1', 'level2', 'createTime', 'updateTime'];
        const duplicateFields = coreFields.filter(field => field in project.extData);
        
        if (duplicateFields.length > 0) {
          extDataIssues.push(`扩展字段包含核心字段: ${duplicateFields.join(', ')}`);
        }
      }
    }
    
    // 检查日期字段是否为合法时间戳
    const dateFields = ['createTime', 'updateTime', 'stateTime', 'startDate', 'deadline'];
    const invalidDateFields = [];
    
    for (const field of dateFields) {
      if (project[field] && (!Number.isInteger(project[field]) || project[field] < 0)) {
        invalidDateFields.push(field);
      }
    }
    
    // 汇总检查结果
    if (missingFields.length > 0 || invalidDateFields.length > 0 || extDataIssues.length > 0) {
      results.failed++;
      results.issues.push({
        projectId: project._id,
        model: project.model || '未知',
        issues: {
          missingFields: missingFields.length > 0 ? missingFields : null,
          invalidDateFields: invalidDateFields.length > 0 ? invalidDateFields : null,
          extDataIssues: extDataIssues.length > 0 ? extDataIssues : null
        }
      });
    } else {
      results.passed++;
    }
  }
  
  // 记录一致性检查结果
  await logOperation(
    OPERATION_TYPES.CONSISTENCY_CHECK,
    'plm_research_project',
    '',
    {
      total: results.total,
      passed: results.passed,
      failed: results.failed,
      issues: results.issues.length > 0 ? results.issues.slice(0, 10) : []
    }
  );
  
  return results;
}

/**
 * 启动定期一致性检查
 */
function startConsistencyCheck() {
  if (!MONITOR_CONFIG.enabled || !MONITOR_CONFIG.enableConsistencyCheck) {
    return;
  }
  
  // 设置定期检查
  setInterval(async () => {
    try {
      console.log('[数据监控] 开始定期数据一致性检查');
      
      // 获取数据库
      const cloud = cloudBase.getCloud();
      const db = cloud.database();
      
      // 获取项目数据
      const result = await db.collection('plm_research_project')
        .limit(1000) // 一次最多检查1000条记录
        .get();
      
      // 进行一致性检查
      const checkResult = await checkDataConsistency(result.data);
      
      console.log(`[数据监控] 一致性检查完成: 总计${checkResult.total}条记录, 通过${checkResult.passed}条, 失败${checkResult.failed}条`);
      
      // 如果有严重问题，触发告警
      if (checkResult.failed > 0 && MONITOR_CONFIG.alerts.enabled) {
        const now = timeUtil.time();
        if (now - errorCache.lastAlertTime > MONITOR_CONFIG.alerts.cooldown) {
          const errors = checkResult.issues.map(issue => ({
            operation: 'consistency_check',
            collection: 'plm_research_project',
            timestamp: now,
            message: `项目 ${issue.model}(${issue.projectId}) 数据一致性问题: ${
              Object.entries(issue.issues)
                .filter(([_, value]) => value)
                .map(([key, value]) => key === 'extDataIssues' ? value.join('; ') : `${key}: ${value.join(', ')}`)
                .join('; ')
            }`
          }));
          
          await triggerAlert(errors);
          errorCache.lastAlertTime = now;
        }
      }
    } catch (error) {
      console.error('[数据监控] 定期一致性检查失败:', error);
    }
  }, MONITOR_CONFIG.consistencyCheckInterval);
  
  console.log('[数据监控] 已启动定期数据一致性检查');
}

// 导出监控模块
module.exports = {
  OPERATION_TYPES,
  logOperation,
  monitorPerformance,
  checkDataConsistency,
  startConsistencyCheck
}; 